package dataStructures;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class Level {
	
	public List<Triple> currentLevel;
	private List<Triple> nextLevel;
	private File tripleCombo;
	private int level;
	
	public Level(){
		this.currentLevel= new ArrayList<Triple>();
		this.nextLevel = new ArrayList<Triple>();
		this.currentLevel.add(new Triple());// add root triple to list
		this.tripleCombo= new File("src/dataStructurs/Info.txt");
		this.level=0;
	}
	
	public  List<Triple> searchFor(Triple goal){
	
		int goalTrip = goal.sumTriple();
		boolean goalFound = false;	
		while(!goalFound){
			List<Triple> current =this.currentLevel;
			this.nextLevel=this.expandToNextLevel(current);
			this.currentLevel.clear();
			this.currentLevel.addAll(this.nextLevel);
			Iterator<Triple> iter = this.currentLevel.iterator();
			if((iter.hasNext())&&(iter.next().sumTriple()==goalTrip)){
				goalFound=true;
			}
		}
		return this.currentLevel;	
	}
	
	public  List<Triple> searchFor(int goal){
		
		int goalTrip = goal;
		boolean goalFound = false;	
		while(!goalFound){
			List<Triple> current =this.currentLevel;
			this.nextLevel=this.expandToNextLevel(current);
			this.currentLevel.clear();
			this.currentLevel.addAll(this.nextLevel);
			Iterator<Triple> iter = this.currentLevel.iterator();
			if((iter.hasNext())&&(iter.next().sumTriple()==goalTrip)){
				goalFound=true;
			}
		}
		return this.currentLevel;	
	}
	
	private List<Triple> expandToNextLevel(List<Triple> current){
		this.level++;
		
		Iterator<Triple> currentIter = current.iterator();
		List<Triple> tempNext = new ArrayList<Triple>();
		List<Triple> newTemp= new ArrayList<Triple>();
		while(currentIter.hasNext()){
			Triple currentTriple =currentIter.next();
	//		System.out.println("Expanding "+ currentTriple.displayTriple());
			Triple max = expandMax(currentTriple);
			Triple mid = expandMid(currentTriple);
			Triple min = expandMin(currentTriple);
			tempNext.add(max);
			tempNext.add(mid);
			tempNext.add(min);
	//		System.out.println("next level= "+ this.displayLevel(tempNext)+"next size=" + tempNext.size());
		
//			System.out.println("after remove"+ this.displayLevel(newTemp));
						
		}	
		newTemp.addAll(removeDuplicates(tempNext));
	//	this.writeLevel(newTemp);
		
		return newTemp;
	}
	
	public void getInfo(Triple goal){
		int goalTrip = goal.sumTriple();
		boolean goalFound = false;	
		while(!goalFound){
			List<Triple> current =this.currentLevel;
			this.nextLevel=this.expandToNextLevel(current);
			this.currentLevel.clear();
			this.currentLevel.addAll(this.nextLevel);
			Iterator<Triple> iter = this.currentLevel.iterator();
			Triple t = iter.next();
			String info =( t.displayTriple()+","+ " , "+t.getExcpetedClonality()+
							","+ t.getMaxClonality());
			this.printline(info);
			if((iter.hasNext())&&(iter.next().sumTriple()==goalTrip)){
				goalFound=true;
			}
		}
	}
	
	private void printline(String line){
		try{
			PrintWriter out = new PrintWriter(new FileOutputStream(this.tripleCombo,true));
			out.println(line);
			out.close();
		}catch (IOException e){}
	}
	
	private List<Triple> removeDuplicates(List<Triple> list){
		if(list.size()==1){
			return list;
		}
		HashSet<Triple> set = new HashSet<Triple>();
		set.addAll(list);
		    list.clear();
		    list.addAll(set);
		
		return list;
	}
	
	private Triple expandMax(Triple trip){
		return new Triple(trip.getMax()+1,trip.getMid(),trip.getMin());
	}
	
	private Triple expandMid(Triple trip){
		return new Triple(trip.getMax(),trip.getMid()+1,trip.getMin());
	}
	
	private Triple expandMin(Triple trip){
		return new Triple(trip.getMax(),trip.getMid(),trip.getMin()+1);
	}
	
	@SuppressWarnings("unused")
	private void writeLevel(List<Triple> list){
		try{
			PrintWriter out = new PrintWriter(new FileOutputStream(this.tripleCombo,true));
			out.println("Current Level"+this.level);
			out.println(this.displayLevel(list));
			out.close();
		}catch (IOException e){}
	}
	
	private String displayLevel(List<Triple> list){
		int size = list.size();
		String result = "";
//	System.out.println("Current Level size = "+ size);
		for (int i=0;i<size;i++){
			result= result+ list.get(i).displayTriple();	
		}
		return result;
	}
	
	

}

